package com.xiaoma.lock.condition.threadab;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 三个线程A B C，A负责发任务序号1、2、3…，BC线程负责处理、B处理偶数任务、C处理奇数任务、怎么保证任务顺序执行？
 */
public class ThreadABTest {

  public static void main(String[] args) throws InterruptedException {
    ReentrantLock reentrantLock = new ReentrantLock();
    Condition conditionA = reentrantLock.newCondition();
    Condition conditionB = reentrantLock.newCondition();

    PrintThread printThread1 = new PrintThread(reentrantLock, conditionA, "print1");
    PrintThread printTherad2 = new PrintThread(reentrantLock, conditionB, "print2");
    printThread1.start();
    printTherad2.start();

    //让printThread1和printThread2先执行
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    for (int i = 0; i < 100; i++) {
      reentrantLock.lock();
      if (i % 2 == 0) {
        printThread1.addInteger(i);
        //唤醒子线程，因为最开始子线程是wait的
        conditionA.signal();
        try {
          //让主线程wait，在 run()里面take值后会signal主线程，那么会继续从该位置执行，继续循环
          conditionA.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      } else {
        printTherad2.addInteger(i);
        conditionB.signal();
        try {
          conditionB.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      reentrantLock.unlock();
    }
  }
}

class PrintThread extends Thread {

  private final ReentrantLock lock;
  private final Condition condition;

  BlockingQueue<Integer> integerList = new LinkedBlockingQueue<Integer>();

  PrintThread(ReentrantLock lock, Condition condition, String threadName) {
    this.lock = lock;
    this.condition = condition;
    setName(threadName);
  }

  public void addInteger(Integer integer) {
    integerList.add(integer);
  }


  @Override
  public void run() {
    while (true) {
      lock.lock();
      try {
        condition.await();
        Integer take = integerList.take();
        System.out.println(Thread.currentThread().getName() + ":" + take);
        condition.signal();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      lock.unlock();
    }
  }
}
